﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using OpenCvSharp;
using WampShare;
using WampSharp.V2;
using WampSharp.V2.Realm;

namespace WampRouter
{
    public class CamServices : ICamService
    {
        /// <summary>
        /// 取消用，并表示状态
        /// </summary>
        private static CancellationTokenSource _cancellationTokenSource = null;
        private static VideoCapture _capture = null;
        private static ISubject<byte[]> _subjectOpen = null;
        private static ISubject<string> _subjectClose = null;
        //private static IWampHostedRealm _realm = null;
        private static Mat _image = new Mat();
        private static VideoCaptureAPIs _videoCaptureAPI;

        public async Task InitService(IWampHostedRealm realm)
        {
            _capture ??= new VideoCapture();//下面再打开0
            //_realm ??= host.RealmContainer.GetRealmByName(ICamServices.RealmStr);
            _subjectOpen ??= realm.Services.GetSubject<byte[]>(ICamService.OpenCamTopic);
            _subjectClose ??= realm.Services.GetSubject<string>(ICamService.CloseCamTopic);
            Task<IAsyncDisposable> registrationTask = realm.Services.RegisterCallee(this);
            await registrationTask;

            _videoCaptureAPI = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? VideoCaptureAPIs.V4L2 : VideoCaptureAPIs.DSHOW;

        }



        #region callee
        public Task<string> OpenCam()
        {
            if (_cancellationTokenSource != null && !_cancellationTokenSource.IsCancellationRequested)
            {
                return Task.FromResult("摄像头已打开，请勿重复操作");
            }

            if (_capture.Open(0, _videoCaptureAPI))
            {
                _cancellationTokenSource = new CancellationTokenSource();
                PubCamOpen();

                return Task.FromResult("打开摄像头成功");
            }
            else
            {
                return Task.FromResult("打开摄像头失败");
            }
        }


        public Task<string> CloseCam()
        {
            _cancellationTokenSource?.Cancel();
            _capture?.Release();
            PubCamClose();
            return Task.FromResult("关闭摄像头");
        }
        #endregion

        #region publish
        private async Task PubCamOpen()
        {
            IObservable<long> timer = Observable.Timer(TimeSpan.FromMilliseconds(0), TimeSpan.FromMilliseconds(33));
            await Console.Out.WriteLineAsync("打开摄像头");
            timer.Subscribe(x =>
            {
                
                // 从摄像头读取一帧
                _capture?.Read(_image);

                // 如果读取到的帧为空，表示没有更多的帧可以读取
                if (_image.Empty())
                {
                    Console.WriteLine("No signal");
                    _cancellationTokenSource?.Cancel();
                    return;
                }
                if (_cancellationTokenSource.IsCancellationRequested) { return; }
                Console.Write('.');
                try
                {
                    _subjectOpen.OnNext(_image.ToBytes());
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    _subjectOpen.OnError(ex);
                    _cancellationTokenSource?.Cancel();
                    return;
                }

            }, _cancellationTokenSource.Token);


            // This line is required in order to release the WebSocket thread, otherwise it will be blocked by the following Console.ReadLine() line.
            await Task.Yield();
        }

        private async Task PubCamClose()
        {
            try
            {
                _subjectClose.OnNext("摄像头已关闭");
                await Console.Out.WriteLineAsync("摄像头已关闭");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                _subjectClose.OnError(ex);
            }
        } 
        #endregion
    }
}
